package oauth

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
)

// 处理OAuth回调
func (m *OAuthMiddleware) handleCallback(w http.ResponseWriter, r *http.Request) error {
	// 获取授权码
	code := r.URL.Query().Get("code")
	if code == "" {
		return fmt.Errorf("no code provided")
	}

	// 使用授权码获取访问令牌
	token, err := m.getAccessToken(code, r)
	if err != nil {
		return err
	}

	// 获取用户信息
	userInfo, err := m.getUserInfo(token)
	if err != nil {
		return err
	}

	// 生成JWT
	jwtToken, err := m.generateToken(userInfo)
	if err != nil {
		return err
	}

	// 设置Cookie
	http.SetCookie(w, &http.Cookie{
		Name:     m.Config.TokenCookieName,
		Value:    jwtToken,
		Path:     "/",
		HttpOnly: true,
		Secure:   r.TLS != nil,
		MaxAge:   86400, // 24小时
	})

	// 从state中获取原始URL
	state := r.URL.Query().Get("state")
	originalURL, err := parseState(state)
	if err != nil {
		originalURL = "/" // 如果解析失败，重定向到根路径
	}

	// 重定向到原始请求页面
	http.Redirect(w, r, originalURL, http.StatusTemporaryRedirect)
	return nil
}

// 获取访问令牌
func (m *OAuthMiddleware) getAccessToken(code string, r *http.Request) (string, error) {
	data := url.Values{}
	data.Set("grant_type", "authorization_code")
	data.Set("code", code)
	data.Set("client_id", m.Config.ClientID)
	data.Set("client_secret", m.Config.ClientSecret)
	data.Set("redirect_uri", fmt.Sprintf("https://%s%s", r.Host, m.Config.CallbackPath))

	resp, err := http.PostForm(m.Config.TokenURL, data)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	var result struct {
		AccessToken string `json:"access_token"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return "", err
	}

	return result.AccessToken, nil
}

// 获取用户信息
func (m *OAuthMiddleware) getUserInfo(accessToken string) (map[string]interface{}, error) {
	req, err := http.NewRequest("GET", m.Config.UserInfoURL, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", "Bearer "+accessToken)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var userInfo map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&userInfo); err != nil {
		return nil, err
	}

	return userInfo, nil
}
